//
//  TablePack.swift
//  Risac
//
//  Created by remy on 2019/4/7.
//  Copyright © 2019 com.Risac. All rights reserved.
//

import UIKit

public protocol ListPack: AnyObject {
    func setRefresh(type: RefreshType, closure: ((RefreshType) -> Void)?)
    func endRefresh(reset: Bool, last: Bool, increasedCount: Int)
    func getModel() -> ListModel
}

/// 数据刷新类型
public struct RefreshType: RawRepresentable {
    
    public let rawValue: UInt32
    public static let none = RefreshType(rawValue: 1 << 0)
    public static let pullDown = RefreshType(rawValue: 1 << 1)
    public static let pullUp = RefreshType(rawValue: 1 << 2)
    public static let loadDown = RefreshType(rawValue: 1 << 3)
    public static let loadUp = RefreshType(rawValue: 1 << 4)
    public static let pullAndLoad = RefreshType(rawValue: 1 << 5)
    public static let loadAndPull = RefreshType(rawValue: 1 << 6)
    
    public init(rawValue: UInt32) {
        self.rawValue = rawValue
    }
    
    public func isAnyOf(_ values: [RefreshType]) -> Bool {
        return values.contains(where: { $0 == self })
    }
}

// MARK: 使用时注意要强引用
public class TablePack: ListPack {
    
    public let view: UITableView
    public let model: TableModel
    public let action: TableAction
    public private(set) var refreshType: RefreshType = .none
    public private(set) var topRefresher: RefreshComponent?
    public private(set) var bottomRefresher: RefreshComponent?
    
    public init(frame: CGRect,
                style: UITableView.Style = .plain,
                target: UIScrollViewDelegate? = nil,
                closure: ((TablePack) -> Void)? = nil) {
        view = UITableView(frame: frame, style: style)
        view.backgroundColor = .clear
        view.separatorStyle = .none
        // 默认关闭高度估算
        view.estimatedRowHeight = 0.0
        view.estimatedSectionHeaderHeight = 0.0
        view.estimatedSectionFooterHeight = 0.0
        // 默认高度自适应,相对布局
        view.rowHeight = UITableView.automaticDimension
        // 默认设为leastNonzeroMagnitude(系统有默认值)
        view.sectionHeaderHeight = .leastNonzeroMagnitude
        view.sectionFooterHeight = .leastNonzeroMagnitude
        if #available(iOS 11.0, *) {
            view.contentInsetAdjustmentBehavior = .never
        }
        model = TableModel()
        action = TableAction()
        if let target = target {
            action.forwardDelegates.add(target)
        }
        closure?(self)
        view.dataSource = model
        view.delegate = action
    }
    
    deinit {
        // MARK: ios11以下版本会出现被监听者已释放kvo还存在从而crash的问题
        view.sac.removeRefreshHeader()
        view.sac.removeRefreshFooter()
    }
    
    public func getModel() -> ListModel {
        return model as ListModel
    }
    
    public func endRefresh(reset: Bool = false,
                           last: Bool = false,
                           increasedCount: Int = 0) {
        topRefresher?.stopRefreshing()
        bottomRefresher?.stopRefreshing()
        if reset {
            // 刷新数据
            if refreshType.isAnyOf([.pullDown, .pullAndLoad, .loadUp]) {
                // 下拉刷新数据设置偏移
                QueueTask.main { [weak self] in
                    self?.view.scrollToTop(animated: false)
                }
            } else if refreshType.isAnyOf([.loadDown, .loadAndPull, .pullUp]) {
                // 上拉刷新数据设置偏移
                QueueTask.main { [weak self] in
                    self?.view.scrollToBottom(animated: false)
                }
            }
        } else {
            // 加载数据
            if refreshType.isAnyOf([.loadDown, .loadAndPull, .pullUp]) {
                // 下拉加载数据设置偏移
                let count = min(max(increasedCount, 0), model.cellItemsCount(at: nil) - 1)
                QueueTask.main { [weak self] in
                    self?.view.scrollToRow(at: IndexPath(row: count, section: 0), at: .top, animated: false)
                }
            }
        }
        noMoreData(last)
    }
    
    public func setRefresh(type: RefreshType, closure: ((RefreshType) -> Void)? = nil) {
        view.alwaysBounceVertical = true
        view.sac.removeRefreshHeader()
        view.sac.removeRefreshFooter()
        topRefresher = nil
        bottomRefresher = nil
        refreshType = type
        guard type != .none else { return }
        if type.isAnyOf([.pullDown, .pullAndLoad]) {
            topRefresher = view.sac.addTopRefresh {
                closure?(.pullDown)
            }
        } else if type.isAnyOf([.loadDown, .loadAndPull]) {
            topRefresher = view.sac.addTopAutoRefresh {
                closure?(.loadDown)
            }
        }
        if type.isAnyOf([.pullUp, .loadAndPull]) {
            bottomRefresher = view.sac.addBottomRefresh {
                closure?(.pullUp)
            }
        } else if type.isAnyOf([.loadUp, .pullAndLoad]) {
            bottomRefresher = view.sac.addBottomAutoRefresh {
                closure?(.loadUp)
            }
        }
    }
    
    public func noMoreData(_ flag: Bool) {
        if let refresher = bottomRefresher as? BottomAutoRefreshView {
            refresher.isNoMoreData = flag
        } else if let refresher = topRefresher as? TopAutoRefreshView {
            refresher.isNoMoreData = flag
        }
    }
}
